/**************************************************************************** **
 * Copyright (C) 2001-2020 Inhand Networks, Inc.
 **************************************************************************** **/

/* ************************************************************************** **
 *     MODULE NAME            : system
 *     LANGUAGE               : C
 *     TARGET ENVIRONMENT     : Any
 *     FILE NAME              : APUE_code.c
 *     FIRST CREATION DATE    : 2022/05/29
 * --------------------------------------------------------------------------
 *     Version                : 1.0
 *     Author                 : EExuke
 *     Last Change            : 2022/05/29
 *     FILE DESCRIPTION       :
** ************************************************************************** */

#include "APUE_code.h"

void aupe_code_test()
{
	my_debug_msg("hello, APUE_code.");
}

/***************************************************************************************
 * Description   : 1.1-myls列出目录下的文件名{{{
 * @param [in ]  : argc, argv
 * @return       : 0
 ***************************************************************************************/
int apue_basic_myls(int argc, char *argv[])
{
	DIR *dp = NULL;
	struct dirent *dirp = NULL;

	if (argc != 2) {
		printf("usage: %s <dir_name>\n", argv[0]);
		return -1;
	}

	if (NULL == (dp = opendir(argv[1]))) {
		fprintf(stderr, "can not open %s\n", argv[1]);
		return -1;
	}

	while (NULL != (dirp = readdir(dp))) {
		printf("%s\n", dirp->d_name);
	}

	closedir(dp);
	return 0;
}
/*}}}*/

/***************************************************************************************
 * Description   : 1.2-exec子进程执行命令{{{
 * @param [in ]  : argc, argv
 * @return       : 0
 ***************************************************************************************/
int apue_basic_execlp(int argc, char *argv[])
{
	char buf[MAXLINE] = {0};
	pid_t pid;
	int status;

	printf("%% "); //命令提示符
	while (NULL != fgets(buf, sizeof(buf), stdin)) {
		if ('\n' == buf[strlen(buf)-1]) {
			buf[strlen(buf)-1] = 0;
		}

		if (0 > (pid = fork())) {
			perror("fork");
			return -1;
		} else if (pid == 0) {
			execlp(buf, buf, (char*)0);
			fprintf(stderr, "counldn't execute %s\n", buf);
			return 127;
		}

		//parent
		if (0 > (pid = waitpid(pid, &status, 0))) {
			fprintf(stderr, "waitpid error\n");
		}
		printf("%% ");
	}

	return 0;
}
/*}}}*/

/***************************************************************************************
 * Description   : 3.1-创建空洞文件{{{
 * @param [in ]  : argc, argv
 * @return       : 0
 ***************************************************************************************/
int apue_file_hole(int argc, char *argv[])
{
	char buf1[] = "abcdefghij";
	char buf2[] = "ABCDEFGHIJ";
	int fd;

	if (0 > (fd = creat("file.hole", (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)))) {
		perror("creat");
		return -1;
	}
	if (strlen(buf1) != write(fd, buf1, strlen(buf1))) {
		perror("write buf1");
		return -1;
	}
	//creat hole
	if (-1 == lseek(fd, 16384, SEEK_SET)) {
		perror("lseek");
		return -1;
	}

	if (strlen(buf2) != write(fd, buf2, strlen(buf2))) {
		perror("write buf2");
		return -1;
	}
	return 0;
}
/*}}}*/

/***************************************************************************************
 * Description   : 4.1-文件类型{{{
 * @param [in ]  : argc, argv
 * @return       : 0
 ***************************************************************************************/
int apue_file_type(int argc, char *argv[])
{
	int i;
	struct stat buf;
	char *ptr = NULL;

	for (i=0; i<argc; i++) {
		printf("%s: ", argv[i]);
		if (lstat(argv[i], &buf) < 0) {
			perror("lstat");
			continue;
		}

		if (S_ISREG(buf.st_mode)) {
			ptr = "regular";
		} else if (S_ISDIR(buf.st_mode)) {
			ptr = "directory";
		} else if (S_ISCHR(buf.st_mode)) {
			ptr = "character special";
		} else if (S_ISBLK(buf.st_mode)) {
			ptr = "block special";
		} else if (S_ISFIFO(buf.st_mode)) {
			ptr = "fifo";
		} else if (S_ISLNK(buf.st_mode)) {
			ptr = "symbolic link";
		} else if (S_ISSOCK(buf.st_mode)) {
			ptr = "socket";
		} else {
			ptr = "** unknown mode **";
		}
		printf("%s\n", ptr);
	}

	return 0;
}
/*}}}*/

/***************************************************************************************
 * Description   : 4.2-切换目录{{{
 * @param [in ]  : argc, argv
 * @return       : 0
 ***************************************************************************************/
int apue_dir_chdir(int argc, char *argv[])
{
	char ptr[128] = {0};

	if (getcwd(ptr, sizeof(ptr)) == NULL) {
		perror("getcwd");
	}
	printf("cwd: %s\n", ptr);

	if (chdir("./single_p/") < 0) {
		perror("chdir");
	}

	if (getcwd(ptr, sizeof(ptr)) == NULL) {
		perror("getcwd");
	}
	printf("cwd: %s\n", ptr);

	return 0;
}
/*}}}*/

/***************************************************************************************
 * Description   : 5.1-内存流操作{{{
 * @param [in ]  : argc, argv
 * @return       : 0
 ***************************************************************************************/
#define BSZ    48
int apue_stdIO_memstream(int argc, char *argv[])
{
	FILE *fp;
	char buf[BSZ];

	memset(buf, 'a', BSZ-2);
	buf[BSZ-2] = '\0';
	buf[BSZ-1] = 'X';
	if ((fp = fmemopen(buf, BSZ, "w+")) == NULL) {
		perror("fmemopen failed");
	}
	printf("initial buffer contents: %s\n", buf);
	fprintf(fp, "hello, world");
	printf("before flush: %s\n", buf);
	fflush(fp);
	printf("after fflush: %s\n", buf);
	printf("len of string in buf = %ld\n", (long)strlen(buf));

	memset(buf, 'b', BSZ-2);
	buf[BSZ-2] = '\0';
	buf[BSZ-1] = 'X';
	fprintf(fp, "hello, world");
	fseek(fp, 0, SEEK_SET);
	printf("after  fseek: %s\n", buf);
	printf("len of string in buf = %ld\n", (long)strlen(buf));

	memset(buf, 'c', BSZ-2);
	buf[BSZ-2] = '\0';
	buf[BSZ-1] = 'X';
	fprintf(fp, "hello, world");
	fclose(fp);
	printf("after fclose: %s\n", buf);
	printf("len of string in buf = %ld\n", (long)strlen(buf));

	return 0;
}
/*}}}*/

/***************************************************************************************
 * Description   : 13.1单示例守护进程{{{
 * @param [in ]  : argc, argv
 * @return       : 0
 ***************************************************************************************/
#define LOCKFILE    "/var/run/daemon.pid"
#define LOCKMODE    (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)
// 文件锁
static int lockfile(int fd)
{
	struct flock fl = {
		.l_type = F_WRLCK,    //加锁类型
		.l_start = 0,         //加锁的开始位置
		.l_whence = SEEK_SET, //位置偏移起点
		.l_len = 0,           //加锁的长度
	};
	return(fcntl(fd, F_SETLK, &fl));
}
//使用文件锁使得进程只能被唯一创建
int apue_already_running(int argc, char *argv[])
{
	int fd;
	char buf[16] = {0};

	fd = open(LOCKFILE, O_RDWR | O_CREAT, LOCKMODE);
	if (fd < 0) {
		syslog(LOG_ERR, "can't open %s: %s", LOCKFILE, strerror(errno));
		exit(1);
	}
	if (lockfile(fd) < 0) {
		if (errno == EACCES || errno == EAGAIN) {
			close(fd); //进程重复时，这里出错退出
			return 1;
		}
		syslog(LOG_ERR, "can't lock %s: %s", LOCKFILE, strerror(errno));
		exit(1);
	}
	ftruncate(fd, 0); //截断为0
	sprintf(buf, "%ld", (long)getpid());
	write(fd, buf, strlen(buf)+1);
	return 0;
}
/*}}}*/

/***************************************************************************************
 * Description   : 18.1终端I/O{{{
 * @param [in ]  : argc, argv
 * @return       : 0
 ***************************************************************************************/
int apue_(int argc, char *argv[])
{
	return 0;
}
/*}}}*/

